package com.asman.oss.my;

import android.annotation.SuppressLint;

import com.alibaba.sdk.android.oss.ClientConfiguration;
import com.alibaba.sdk.android.oss.ClientException;
import com.alibaba.sdk.android.oss.OSS;
import com.alibaba.sdk.android.oss.OSSClient;
import com.alibaba.sdk.android.oss.ServiceException;
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback;
import com.alibaba.sdk.android.oss.common.auth.OSSAuthCredentialsProvider;
import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider;
import com.alibaba.sdk.android.oss.internal.OSSAsyncTask;
import com.alibaba.sdk.android.oss.model.OSSRequest;
import com.alibaba.sdk.android.oss.model.PutObjectRequest;
import com.alibaba.sdk.android.oss.model.PutObjectResult;
import com.asman.oss.Config;
import com.asman.oss.OSSUtils;

import java.io.File;
import java.util.UUID;

import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.subscribers.ResourceSubscriber;

/**
 * Created by yubaokang on 2017/2/13.
 */
public class OSSUpload {

    public static OSSUpload instance;

    public static OSSUpload get(String bucketName, String endpoint) {
        if (instance == null) {
            instance = new OSSUpload(Config.STS_SERVER_URL, endpoint, bucketName, "");
        }
        return instance;
    }

    private OSS oss;
    private String bucketName;

    /**
     * @param stsServer  应用服务器地址
     * @param endpoint   远程OSS服务器地址
     * @param bucketName String
     * @param dir        自己后台提供：OSS的根文件夹名称
     */
    private OSSUpload(String stsServer, String endpoint, String bucketName, String dir) {
        this.bucketName = bucketName;
        // 推荐使用OSSAuthCredentialsProvider，token过期后会自动刷新。
        OSSCredentialProvider credentialProvider = new OSSAuthCredentialsProvider(stsServer);
        //config
        ClientConfiguration conf = new ClientConfiguration();
        conf.setConnectionTimeout(15 * 1000); // 连接超时时间，默认15秒
        conf.setSocketTimeout(15 * 1000); // Socket超时时间，默认15秒
        conf.setMaxConcurrentRequest(5); // 最大并发请求数，默认5个
        conf.setMaxErrorRetry(2); // 失败后最大重试次数，默认2次
        oss = new OSSClient(OSSUtils.getInstance(), endpoint, credentialProvider, conf);
    }

    private String getUploadObject(String filePath) {
        String prefix = filePath.substring(filePath.lastIndexOf("."));//获取后缀名 比如：".gif"
        return UUID.randomUUID().toString() + prefix;
    }

    public interface OnUploadListener {
        void onProgress(int progress);//0-100

        void onSuccess(PutObjectRequest request, PutObjectResult result);

        void onFailed(PutObjectRequest request, ClientException clientExcepion, ServiceException serviceException);
    }

    @SuppressLint("CheckResult")
    public OSSAsyncTask<PutObjectResult> asyncPutImage(String localFile, final OnUploadListener listener) {
        String object = getUploadObject(localFile);
        if (object.equals("")) return null;
        File file = new File(localFile);
        if (!file.exists()) return null;
        // 构造上传请求
        PutObjectRequest put = new PutObjectRequest(bucketName, object, localFile);

        // 文件元信息的设置是可选的。
//        ObjectMetadata metadata = new ObjectMetadata();
//        metadata.setContentType("application/octet-stream"); // 设置content-type。
//        metadata.setContentType("video/mp4"); // 设置content-type。
//        metadata.setContentMD5(BinaryUtil.calculateBase64Md5(uploadFilePath)); // 校验MD5。
//        put.setMetadata(metadata);

        put.setCRC64(OSSRequest.CRC64Config.YES);
        // 异步上传时可以设置进度回调
        put.setProgressCallback((request, currentSize, totalSize) -> {
            int progress = (int) (100 * currentSize / totalSize);
            listener.onProgress(progress);
        });
        return oss.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
            @Override
            public void onSuccess(final PutObjectRequest request, final PutObjectResult result) {
                Flowable.just(1).observeOn(AndroidSchedulers.mainThread()).subscribe(new ResourceSubscriber<Integer>() {
                    @Override
                    public void onNext(Integer integer) {
                        listener.onSuccess(request, result);
                    }

                    @Override
                    public void onError(Throwable t) {
                    }

                    @Override
                    public void onComplete() {
                    }
                });
            }

            @Override
            public void onFailure(final PutObjectRequest request, final ClientException clientExcepion, final ServiceException serviceException) {
                Flowable.just(1).observeOn(AndroidSchedulers.mainThread()).subscribe(new ResourceSubscriber<Integer>() {
                    @Override
                    public void onNext(Integer integer) {
                        listener.onFailed(request, clientExcepion, serviceException);
                    }

                    @Override
                    public void onError(Throwable t) {
                    }

                    @Override
                    public void onComplete() {
                    }
                });
            }
        });
    }
}